﻿unit UMainFrm;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, pngimage, ExtCtrls, ComCtrls, StdCtrls, UrlMon, uDownThread, WinProcs, ShellAPI;

type
  TFrmMain = class(TForm)
    img1: TImage;
    pbDownloader: TProgressBar;
    lblProcess: TLabel;
    procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
    procedure img1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
  private
    { Private declarations }
    FDownThread: TDownThread;
    FDownloadUrl: string;
    FDownloadFilePath: string;
    FDownloadPkgTpye: string;
    FIsSlient: Boolean;
    procedure DoWM_DownProgres(var Msg: TMessage); message WM_DownloadProgress;
    procedure DoWM_DownloadCompleted(var Msg: TMessage); message WM_DownloadCompleted;
    function RunWait(FileName: string; Visibility: Integer): THandle;
  public
    { Public declarations }
    function InitParams(const url, pkgType: string; const isSilent: Boolean): Boolean;
    procedure StartDownload();
    destructor Destroy; override;
  end;

var
  FrmMain: TFrmMain;

implementation

{$R *.dfm}

function TFrmMain.InitParams(const url, pkgType: string; const isSilent: Boolean): Boolean;
begin
  Result := True;
  FDownloadUrl := '';
  FDownloadPkgTpye := '';

  FIsSlient := isSilent;

  if (url <> '') then
  begin
    FDownloadUrl := url;
  end;

  if CompareStr(LowerCase(pkgType), '/e') = 0 then
  begin
    FDownloadPkgTpye := 'EXE';
  end
  else if CompareStr(LowerCase(pkgType), '/z') = 0 then
  begin
    FDownloadPkgTpye := 'ZIP';
  end
  else
  begin
    Result := False;
  end;

end;

procedure TFrmMain.StartDownload();
var
  tempDir: array[0..MAX_PATH] of Char;
  tempDirStr: string;
begin
  try
    if Assigned(FDownThread) then
    begin
      FDownThread.Terminate;
      FDownThread.WaitFor;
      FDownThread.Free;
      FDownThread := nil;
    end;

    GetTempPath(MAX_PATH, @tempDir);
    tempDirStr := StrPas(tempDir);

    if CompareStr(FDownloadPkgTpye, 'EXE') = 0 then
    begin
      FDownloadFilePath := tempDirStr + '\\bos_updater_' + FormatDateTime('hhnnss', Now()) + '.exe';
    end
    else if CompareStr(FDownloadPkgTpye, 'ZIP') = 0 then
    begin
      FDownloadFilePath := tempDirStr + '\\bos_updater_' + FormatDateTime('hhnnss', Now()) + '.zip';
    end;

    if not Assigned(FDownThread) then
    begin
      FDownThread := TDownThread.Create(FDownloadUrl, FDownloadFilePath, Self.Handle);
      FDownThread.Start;
    end;
  except
    // do something
    // 下载失败
    if not FIsSlient then
    begin
      Application.MessageBox('下载更新包失败，请访问美丽科学官网下载最新版本安装！', '错误', MB_ICONERROR);
    end;
    Application.Terminate;
  end;
end;

destructor TFrmMain.Destroy;
begin

  inherited;
end;

procedure TFrmMain.DoWM_DownProgres(var Msg: TMessage);
begin
  pbDownloader.Position := Msg.LParam;
  Self.lblProcess.Caption := Format('新版本更新中，已完成%d', [Msg.LParam]) + '%';
end;

procedure TFrmMain.DoWM_DownloadCompleted(var Msg: TMessage);
var
  unzipCmd: string;
begin
  // 下载完成，执行后续动作
  if Msg.LParam = 0 then
  begin
    // 下载成功
    //Application.MessageBox('下载成功！', '提示', MB_ICONINFORMATION);
    Self.lblProcess.Caption := '新版本下载完成，正在更新...';
    try
      if not FileExists(FDownloadFilePath) then
      begin
        raise Exception.Create('更新文件不存在');
      end;

      // 执行更新包，然后退出更新程序
      if CompareStr(FDownloadPkgTpye, 'EXE') = 0 then
      begin
        // 将exe运行起来，然后退出
        //WinExec(PAnsiChar(AnsiString(FDownloadFilePath)), SW_SHOWNORMAL);
        ShellExecute(handle, 'open', PWideChar(WideString(FDownloadFilePath)), '', nil, SW_SHOWNORMAL);
      end
      else if CompareStr(FDownloadPkgTpye, 'ZIP') = 0 then
      begin
        // 将zip解压至更新程序exe所在路径
        // !!!这种更新方式无法更新更新程序自身，最好是将更新程序拷贝至temp目录后，再运行
        unzipCmd := '7z.exe x "' + FDownloadFilePath + '" -o"' + ExtractFilePath(ParamStr(0)) + '" -y';
        RunWait(unzipCmd, SW_NORMAL);
        DeleteFile(PWideChar(FDownloadFilePath));
      end;
    except
    begin
      if not FIsSlient then
      begin
        Application.MessageBox('下载更新包失败，请访问美丽科学官网下载最新版本安装！', '错误', MB_ICONERROR);
      end;
    end;  
    end;

    // 更新程序退出
    Application.Terminate;
  end;

  if Msg.LParam = -1 then
  begin
    // 下载失败
    if not FIsSlient then
    begin
      Application.MessageBox('下载更新包失败，请访问美丽科学官网下载最新版本安装！', '错误', MB_ICONERROR);
    end;
    Application.Terminate;
  end;
end;

procedure TFrmMain.FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
begin
  // 无边框窗口移动
  ReleaseCapture;
  PostMessage(Self.Handle, WM_SYSCOMMAND, SC_MOVE + 1, 0);
end;

procedure TFrmMain.img1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
begin
  // 无边框窗口移动
  ReleaseCapture;
  PostMessage(Self.Handle, WM_SYSCOMMAND, SC_MOVE + 1, 0);
end;

function TFrmMain.RunWait(FileName: string; Visibility: Integer): THandle;
var
  zAppName: array[0..512] of Char;
  zCurDir: array[0..255] of Char;
  WorkDir: string;
  StartupInfo: TStartupInfo;
  ProcessInfo: TProcessInformation;
begin
  try
    StrPCopy(zAppName, FileName);
    GetDir(0, WorkDir);
    StrPCopy(zCurDir, WorkDir);
    FillChar(StartupInfo, SizeOf(StartupInfo), #0);
    StartupInfo.cb := SizeOf(StartupInfo);
    StartupInfo.dwFlags := STARTF_USESHOWWINDOW;
    StartupInfo.wShowWindow := Visibility;
    if not CreateProcess(nil, zAppName, nil, nil, false, Create_NEW_CONSOLE or NORMAL_PRIORITY_CLASS, nil, nil, StartupInfo, ProcessInfo) then
    begin
      result := 0;
      Exit;
    end
    else
    begin
      WaitForSingleObject(ProcessInfo.hProcess, 10000);
      GetExitCodeProcess(ProcessInfo.hProcess, result);
    end;
  finally
  end;
end;

end.

